using System;

namespace GeoFramework.IO.Bluetooth
{
	/// <summary>
	/// Represents a Bluetooth device address.
	/// </summary>
	public sealed class BluetoothAddress
	{
		private byte[] pBuffer;
		private string pAddress;

		/// <summary>
		/// Initializes a new instance of the <see cref="BluetoothAddress"/>.
		/// </summary>
		public BluetoothAddress()
			: this(new byte[6])
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="BluetoothAddress"/> class with the specified address.
		/// </summary>
		/// <param name="address"><see cref="Int64"/> representation of the address.</param>
		public BluetoothAddress(long address) 
			: this(BitConverter.GetBytes(address))
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="BluetoothAddress"/> class with the specified address.
		/// </summary>
		/// <param name="address">Address as 6 byte array.</param>
		public BluetoothAddress(byte[] address) 
		{
			if(address.Length == 6)
			{
				pBuffer = address;
				
				pAddress = pBuffer[5].ToString("X2") + ":"
					+ pBuffer[4].ToString("X2") + ":"
					+ pBuffer[3].ToString("X2") + ":"
					+ pBuffer[2].ToString("X2") + ":"
					+ pBuffer[1].ToString("X2") + ":"
					+ pBuffer[0].ToString("X2");
			}
			else
			{
				throw new ArgumentException();
			}
		}

		public BluetoothAddress(string address)
		{
			pBuffer = new byte[6];

			if(address.IndexOf(":") > -1)
			{
				//assume address in standard hex format 00:00:00:00:00:00
				//split on colons
				string[] sbytes = address.Split(':');
				for(int ibyte = 0; ibyte < 6; ibyte++)
				{
					//parse hex byte in reverse order
					pBuffer[ibyte] = byte.Parse(sbytes[5 - ibyte], System.Globalization.NumberStyles.HexNumber);
				}
			}
			else
			{
				//assume specified as long integer
				long value = long.Parse(address, System.Globalization.NumberStyles.HexNumber);
				byte[] addr = BitConverter.GetBytes(value);
				Array.Copy(addr, 0, pBuffer, 0, 6);
			}

			pAddress = pBuffer[5].ToString("X2") + ":"
				+ pBuffer[4].ToString("X2") + ":"
				+ pBuffer[3].ToString("X2") + ":"
				+ pBuffer[2].ToString("X2") + ":"
				+ pBuffer[1].ToString("X2") + ":"
				+ pBuffer[0].ToString("X2");
		}

		/// <summary>
		/// Converts the string representation of a Bluetooth address to a new <see cref="BluetoothAddress"/> instance.
		/// </summary>
		/// <param name="address">A string containing an address to convert.</param>
		/// <returns>New BluetoothAddress instance.</returns>
		/// <remarks>Address must be specified in hex format separated by the colon character e.g. 00:00:00:00:00:00, or as a long hex formatted integer.</remarks>
		public static BluetoothAddress Parse(string address)
		{
			return new BluetoothAddress(address);
		}


		/// <summary>
		/// Returns the internal byte array
		/// </summary>
		/// <returns></returns>
		public byte[] ToByteArray()
		{
			return pBuffer;
		}

		public bool Equals(BluetoothAddress obj)
		{
			return ToString() == obj.ToString();
		}

		public override bool Equals(object obj)
		{
			return Equals((BluetoothAddress)obj);
		}

		public override int GetHashCode()
		{
			return pAddress.GetHashCode();
		}

		/// <summary>
		/// Returns the Bluetooth address as a long integer.
		/// </summary>
		/// <returns></returns>
		public long ToInt64()
		{
			return BitConverter.ToInt64(pBuffer, 0);
		}

		/// <summary>
		/// Converts the address to its equivalent string representation.
		/// </summary>
		/// <returns>The string representation of this instance.</returns>
		public override string ToString()
		{
			return pAddress;
		}

		/// <summary>
		/// Provides a null Bluetooth address.
		/// This field is read-only.
		/// </summary>
		public static readonly BluetoothAddress Empty = new BluetoothAddress();

	}
}
